using System;
using System.Collections.Generic;
using Cysharp.Threading.Tasks;

namespace EventBus
{
    public class Broadcast : IBroadcast
    {
        private readonly Sender _sender;
        private readonly IList<DelegateReference> _callbacks = new List<DelegateReference>();

        public Broadcast(Sender sender)
        {
            _sender = sender;
        }

        public void AddListener(string eventName, object callback)
        {
            _callbacks.Add(new DelegateReference((Delegate)callback));
        }

        public int RemoveListener(string eventName, object callback)
        {
            foreach (var delegateRef in _callbacks)
            {
                if (delegateRef.TargetEquals((Delegate)callback))
                {
                    _callbacks.Remove(delegateRef);
                    break;
                }
            }

            return _callbacks.Count;
        }

        public async UniTask<TResult> BroadcastFuncAsync<T1, T2, T3, T4, T5, T6, T7, T8, TResult>(string eventName,
            int argCount, T1 arg1,
            T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8)
        {
            TResult result = default;
            foreach (var delegateRef in _callbacks)
            {
                if (delegateRef.Target == null)
                    continue;
                result = await _sender.SendFuncAsync<T1, T2, T3, T4, T5, T6, T7, T8, TResult>(delegateRef.Target,
                    argCount, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
            }

            return result;
        }

        public async UniTask<bool> BroadcastActionAsync<T1, T2, T3, T4, T5, T6, T7, T8>(string eventName, int argCount,
            T1 arg1, T2 arg2,
            T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8)
        {
            foreach (var delegateRef in _callbacks)
            {
                if (delegateRef.Target == null)
                    continue;
                await _sender.SendActionAsync(delegateRef.Target, argCount, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
                    arg8);
            }

            return IsExistListeners();
        }

        public bool BroadcastAction<T1, T2, T3, T4, T5, T6, T7, T8>(string eventName, int argCount, T1 arg1,
            T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8)
        {
            foreach (var delegateRef in _callbacks)
            {
                if (delegateRef.Target == null)
                    continue;
                _sender.SendAction(delegateRef.Target, argCount, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
            }

            return IsExistListeners();
        }

        public TResult BroadcastFunc<T1, T2, T3, T4, T5, T6, T7, T8, TResult>(string eventName, int argCount, T1 arg1,
            T2 arg2, T3 arg3,
            T4 arg4,
            T5 arg5, T6 arg6, T7 arg7, T8 arg8)
        {
            TResult result = default;
            foreach (var delegateRef in _callbacks)
            {
                if (delegateRef.Target == null)
                    continue;
                result = _sender.SendFunc<T1, T2, T3, T4, T5, T6, T7, T8, TResult>(delegateRef.Target, argCount, arg1,
                    arg2, arg3, arg4, arg5, arg6, arg7, arg8);
            }

            return result;
        }

        private bool IsExistListeners()
        {
            return _callbacks.Count > 0;
        }
    }
}